﻿//This filter is tested and seems to work correctly

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

namespace LowLevelGraphics.Filter
{
    //TODO: make this more flexible for each color space maybe...
    /// <summary>
    /// Rounds the color components of each channel
    /// </summary>
    public class RoundColors : BaseImageFilter
    {
        protected byte m_nValue = 10;

        /// <summary>
        /// Initializes a new instance of the <see cref="RoundColors"/> class.
        /// </summary>
        public RoundColors()
        {
        }


        /// <summary>
        /// Initializes a new instance of the <see cref="RoundColors"/> class.
        /// </summary>
        /// <param name="_nValue">The _n value.</param>
        public RoundColors(byte _nValue)
        {
            m_nValue = _nValue;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="RoundColors"/> class.
        /// </summary>
        /// <param name="_roundColorsUnsafe">The _round colors unsafe.</param>
        internal RoundColors(RoundColors _roundColorsUnsafe)
        {
            this.m_nValue = _roundColorsUnsafe.m_nValue;
        }

        /// <summary>
        /// Gets or sets the value.
        /// </summary>
        /// <value>The value.</value>
        public byte Value
        {
            get { return m_nValue; }
            set { m_nValue = value; }
        }

        /// <summary>
        /// Execute this Filter
        /// A Debug Statement is written if a concrete Filter is called
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            UnsafeBitmap bitmap = _bitmap;
            // GDI+ still lies to us - the return format is BGR, NOT RGB.
            BitmapData bmData = bitmap.BitmapData; //bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

            int stride = bmData.Stride;
            IntPtr Scan0 = bmData.Scan0;

            int nWidth = bitmap.Width;
            int nHeight = bitmap.Height;

            byte r = 0;
            byte g = 0;
            byte b = 0;

            Color color = Color.Transparent;

            int nOffset = 0;
            int nLineOffset = 0;

            unsafe
            {
                nOffset = 0;
                nLineOffset = bitmap.OffsetPointerIncrease; //= stride - nWidth * 3;
                int nCount = bitmap.BytesPerPixelCount;
                int y = 0;
                int x = 0;

                for (y = 0; y < nHeight; ++y)
                {
                    for (x = 0; x < nWidth; ++x)
                    {
                        r = Marshal.ReadByte(Scan0, nOffset + 2);
                        g = Marshal.ReadByte(Scan0, nOffset + 1);
                        b = Marshal.ReadByte(Scan0, nOffset);

                        color = Color.FromArgb(r, g, b);

                        //TODO: this might be sped up (RoundColorsUnsafe)
                        color = ColorFunctions.ColorComponentRound(color, MidpointRounding.ToEven, m_nValue);

                        Marshal.WriteByte(Scan0, nOffset + 2, color.R);
                        Marshal.WriteByte(Scan0, nOffset + 1, color.G);
                        Marshal.WriteByte(Scan0, nOffset, color.B);
                        nOffset += nCount;
                    }
                    nOffset += nLineOffset;
                }
            }

            return _bitmap;
        }

        /// <summary>
        /// This is used to clone a filter, each filter must implement it's own clone functionality
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new RoundColors(this);
        }
    }
}
